#include "SoundManager.h"

using namespace GalliumEngine;

SoundManager::SoundManager(void) : Singleton<SoundManager>()
{

}

SoundManager::~SoundManager(void)
{

}

bool SoundManager::initialize()
{
	initialized = false;

	result = FMOD::System_Create(&system);

	result = system->getVersion(&version);

	if (version < FMOD_VERSION)
	{
		Logger::getInstance()->write(StringUtils::format("Error! You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION));
		return false;
	}

	result = system->getNumDrivers(&numdrivers);

	if (numdrivers == 0)
	{
		result = system->setOutput(FMOD_OUTPUTTYPE_NOSOUND);
		return false;
	}
	else
	{
		result = system->getDriverCaps(0, &caps, 0, &speakermode);

		result = system->setSpeakerMode(speakermode);

		if (caps & FMOD_CAPS_HARDWARE_EMULATED)
		{
			Logger::getInstance()->write("The 'Acceleration' slider set to off! This is really bad for latency!");

			result = system->setDSPBufferSize(1024, 10);
		}

		result = system->getDriverInfo(0, name, 256, 0);

		if (strstr(name, "SigmaTel"))
		{
			result = system->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0,FMOD_DSP_RESAMPLER_LINEAR);
		}
	}

	result = system->init(128, FMOD_INIT_NORMAL, 0);

	if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
	{
		result = system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
		result = system->init(100, FMOD_INIT_NORMAL, 0);
	}

	initialized = true;

	return true;
}

void SoundManager::deInitialize()
{
}

void SoundManager::createSound(std::string id, std::string fileName)
{
	createSound(id,fileName,SOUND_TYPE::SOUND_TYPE_3D_SOUND);
}

void SoundManager::createStream(std::string id, std::string fileName)
{
	createSound(id,fileName,SOUND_TYPE::SOUND_TYPE_2D_SOUND);
}

void SoundManager::createLoopedSound(std::string id, std::string fileName)
{
	createSound(id,fileName,SOUND_TYPE::SOUND_TYPE_3D_SOUND);
}

void SoundManager::createLoopedStream(std::string id, std::string fileName)
{
	createSound(id,fileName,SOUND_TYPE::SOUND_TYPE_2D_SOUND_LOOPED);
}

Sound* SoundManager::getSound(std::string _id)
{
	sound_map_const_itr itr = sounds.find(_id);

	if(itr != sounds.end())
	{
		return (itr->second);
	}

	return NULL;
}

void SoundManager::createSound(std::string id, std::string fileName, SOUND_TYPE::SOUNDTYPE soundType)
{
	Sound* sound = new Sound(id);

	FMOD::Sound* fsound;;

	switch (soundType)
	{
		case SOUND_TYPE::SOUND_TYPE_3D_SOUND:
		{
			result = system->createSound(fileName.c_str(), FMOD_3D | FMOD_HARDWARE, 0, &fsound);
			break;
		}
 
		case SOUND_TYPE::SOUND_TYPE_3D_SOUND_LOOPED:
		{
			result = system->createSound(fileName.c_str(), FMOD_LOOP_NORMAL | FMOD_3D | FMOD_HARDWARE, 0, &fsound);
			break;
		}
 
		case SOUND_TYPE::SOUND_TYPE_2D_SOUND:
		{
			result = system->createStream(fileName.c_str(), FMOD_DEFAULT, 0, &fsound);
			break;
		}
 
		case SOUND_TYPE::SOUND_TYPE_2D_SOUND_LOOPED:
		{
			result = system->createStream(fileName.c_str(), FMOD_LOOP_NORMAL | FMOD_2D | FMOD_HARDWARE, 0, &fsound);
			break;
		}
 
		default:
		{
			Logger::getInstance()->write("SoundManager::CreateSound could not load sound '" + fileName + "' (invalid soundType)");
		}
	}

	if (result != FMOD_OK)
	{
		Logger::getInstance()->write("SoundManager::CreateSound could not load sound '" + fileName + "'  FMOD Error:" + FMOD_ErrorString(result));
	}

	sound->setSound(fsound);

	sounds.insert(sound_pair(id,sound));
}

void SoundManager::setListenerAttributes(Vector3 _position,
	Vector3 _velocity,
	Vector3 _forward,
	Vector3 _up)
{
	FMOD_VECTOR position = { _position[0], _position[1], _position[2] };
	FMOD_VECTOR velocity = { _velocity[0], _velocity[1], _velocity[2] };
	FMOD_VECTOR forward = { _forward[0], _forward[1], _forward[2] };
	FMOD_VECTOR up = { _up[0], _up[1], _up[2] };

	system->set3DListenerAttributes(1,&position,&velocity,&forward,&up);
}

FMOD::System* SoundManager::getSystem()
{
	return system;
}